#pragma once

#include "UdpServer.hpp"
#include <unordered_map>

class User
{
public:
    User(std::string user_ip, uint16_t user_port):_user_ip(user_ip), _user_port(user_port)
    {}
    ~User()
    {}
    std::string get_user_ip()
    {
        return _user_ip;
    }
    uint16_t get_user_port()
    {
        return _user_port;
    }
private:
    std::string _user_ip;
    uint16_t _user_port;
};

class OnlineClient
{
public:
    OnlineClient()
    {}
    bool is_online(int socketfd, std::string user_ip, uint16_t user_port)//判断该用户是否已经上线了
    {
        std::string response;
        std::string _user_port = std::to_string(user_port);
        std::string id = user_ip + "-" + _user_port;
        auto it = online_client.find(id);
        if(it == online_client.end()) 
        {
            response = "please online at first! you should enter \"online\" to make it!";
            struct sockaddr_in client;
            bzero(&client, sizeof(client));

            client.sin_family = AF_INET;
            client.sin_port = htons(user_port);
            client.sin_addr.s_addr = inet_addr(user_ip.c_str());
            int n = sendto(socketfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));
            if(n == -1)
            {
                std::cerr << errno << ": "<< strerror(errno) << std::endl;
                exit(SENDTO_ERR);
            }
            return false;
        }
        return true;
    }
    void add_user(int socketfd, std::string user_ip, uint16_t user_port)//增加一名新用户
    {
        std::string response;

        std::string _user_port = std::to_string(user_port);
        std::string id = user_ip + "-" + _user_port;
        User new_user(user_ip, user_port);
        online_client.insert(std::make_pair(id, new_user));

        response = "online success!";
        struct sockaddr_in client;
        bzero(&client, sizeof(client));

        client.sin_family = AF_INET;
        client.sin_port = htons(user_port);
        client.sin_addr.s_addr = inet_addr(user_ip.c_str());
        int n = sendto(socketfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));
        if(n == -1)
        {
            std::cerr << errno << ": "<< strerror(errno) << std::endl;
            exit(SENDTO_ERR);
        }
    }
    void del_user(int socketfd, std::string user_ip, uint16_t user_port)//删除用户
    {
        if(is_online(socketfd, user_ip, user_port))
        {
            std::string response;

            std::string _user_port = std::to_string(user_port);
            std::string id = user_ip + "-" + _user_port;
            online_client.erase(id);
            
            response = "del success!";
            struct sockaddr_in client;
            bzero(&client, sizeof(client));

            client.sin_family = AF_INET;
            client.sin_port = htons(user_port);
            client.sin_addr.s_addr = inet_addr(user_ip.c_str());
            int n = sendto(socketfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));
            if(n == -1)
            {
                std::cerr << errno << ": "<< strerror(errno) << std::endl;
                exit(SENDTO_ERR);
            }
        }
    }
    void broadcast_message(int socketfd, std::string user_ip, uint16_t user_port, const std::string& message)//将消息传给该聊天室的每一个在线用户
    {   
        std::string _user_port = std::to_string(user_port);
        std::string id = user_ip + "-" + _user_port;
        for(auto &it: online_client)
        {
            struct sockaddr_in client;
            bzero(&client, sizeof(client));

            client.sin_family = AF_INET;
            client.sin_port = htons(it.second.get_user_port());
            client.sin_addr.s_addr = inet_addr(it.second.get_user_ip().c_str());

            std::string msg = id + "# " + message;

            int n = sendto(socketfd, msg.c_str(), msg.size(), 0, (struct sockaddr*)&client, sizeof(client));
            if(n == -1)
            {
                std::cerr << errno << ": "<< strerror(errno) << std::endl;
                exit(SENDTO_ERR);
            }
        }
    }
    ~OnlineClient()
    {}
private:
    std::unordered_map<std::string, User> online_client;
};